from py2neo import Graph, Node, NodeMatcher, Relationship, Subgraph
# 数据库操作方法
# 上一级再上一级
from db.databaseOperation import (
    connect,
    addNodeByTx,
    addNodes,
    deleteAllNodes
)
# 工具方法
from utils.printMessage import (
    logMessage
)
from ..common import (
    getNodeTypeData,
    getRelationshipTypeData
)
from .getData import (
    # 常量
    HERO_NODE_RELATIONSHIP_KEY,
    # 方法
    getHeroDataAndDeleteUselessAttr,
    getHeroLocationData,
    getHeroRoleData,
)


'''
    处理英雄节点的相关函数
'''
# 处理英雄数据并且创建英雄的节点
def parseDataAndCreateHeroNode(tx, nodeType, heroData, nodeName):
    heroNodeData = {}
    # 处理英雄数据，用一个新的对象只保留需要的数据
    for key in heroData:
        if key in HERO_NODE_RELATIONSHIP_KEY:
            continue
        else:
            heroNodeData[key] = heroData[key]
            # if key == 'alias':
            #     # 用来匹配区域那边的结点，因为要区域那边需要匹配
            #     heroNodeData['matchAlias'] = heroData[key].lower()
    heroNode = addNodeByTx(tx, nodeType, heroNodeData, nodeName)
    return heroNode

# 匹配英雄对应的位置节点
def matchAndGetNodes(matcher, nodeType, heroData, key):
    nodes = matcher.match(nodeType)
    matchArr = heroData[key]
    resultNodes = []
    for node in nodes:
        if node['type'] in matchArr:
            resultNodes.append(node)
    return resultNodes

# 连接英雄节点与其他节点
def connectHeroNodeWithOtherNodes(tx, heroNode, otherNodes, relationshipAttr):
    relationshipList = []
    # 这里使用两个变量装载我们需要的内容，不改变传入的参数，实现纯函数
    relationshipType = ''
    otherAttrList = {}
    for key in relationshipAttr:
        if key == 'type':
            relationshipType = relationshipAttr[key]
        else:
            otherAttrList[key] = relationshipAttr[key]
    for matchNode in otherNodes:
        relationship = Relationship(heroNode, relationshipType, matchNode, **otherAttrList)
        relationshipList.append(relationship)
    subgraphResult = Subgraph(relationships=relationshipList)
    tx.create(subgraphResult)
'''
函数名称：
    createHeroRoleNode
作用：
    将英雄角色节点载入到数据库中
参数：
    graph: 图数据库对象
    nodeType: 节点的类型
    data: 处理的数据 
'''
def createHeroNodeAndLinkLocationAndRole(graph, nodeType, data, relationshipType):
    tx = graph.begin()
    # 用来查找节点的对象
    matcher = NodeMatcher(graph)
    count = 1
    for heroData in data:
        # 1.创建英雄节点
        heroNode = parseDataAndCreateHeroNode(tx, nodeType['hero']['type'], heroData, nodeType['hero']['desc'])
        # logMessage("创建英雄节点成功")
        # 2.匹配对应位置的节点
        locationNodes = matchAndGetNodes(matcher, nodeType['heroLocation']['type'], heroData, HERO_NODE_RELATIONSHIP_KEY[1])
        # logMessage("匹配对应位置的节点成功")
        # 3.匹配对应角色的节点
        roleNodes = matchAndGetNodes(matcher, nodeType['heroRole']['type'], heroData, HERO_NODE_RELATIONSHIP_KEY[0])
        # logMessage("匹配对应角色的节点成功")
        # 4.连接英雄节点和位置节点
        connectHeroNodeWithOtherNodes(tx, heroNode, locationNodes, relationshipType['heroLocation'])
        # logMessage("连接英雄节点和位置节点成功")
        # 5.连接英雄节点和角色节点
        connectHeroNodeWithOtherNodes(tx, heroNode, roleNodes, relationshipType['heroRole'])
        count += 1
    try:
        tx.commit()
        logMessage("创建英雄节点以及连接相应边成功")
    except:
        logMessage("创建英雄节点以及连接相应边失败")

# 装载数据
def loadData():
    # 1.获取三个节点的数据
    hero_data = getHeroDataAndDeleteUselessAttr()
    hero_location_data = getHeroLocationData()
    hero_role_data = getHeroRoleData()

    # 2.获取节点类型数据
    node_type_data = getNodeTypeData()
    
    # 3.获取边类型数据
    relationship_type_data = getRelationshipTypeData()
    '''
        装在三个节点的数据，注意顺序，先把位置节点以及角色节点装入
        因为英雄数据中会包含对应的位置和相应的角色
    '''
    # 4.连接数据库并返回对象
    graph = connect()
    
    # 5.新增位置节点
    addNodes(graph, node_type_data['heroLocation']['type'], hero_location_data, node_type_data['heroLocation']['desc'])
    logMessage("新增位置节点成功")
    
    # 6.新增角色节点
    addNodes(graph, node_type_data['heroRole']['type'], hero_role_data, node_type_data['heroRole']['desc'])
    logMessage("新增角色节点")

    # 7.新增英雄节点，同时会连接对应的角色和位置
    createHeroNodeAndLinkLocationAndRole(graph, node_type_data, hero_data, relationship_type_data)